IMarshal - Default Implementation
COM uses its
own internal implementation of the IMarshal
COM s default
implementation of IMarshal uses a generic proxy for each object, and
creates individual stubs and proxies, as they are needed, for each interface
implemented on the object. This mechanism is necessary because COM cannot know
in advance what particular interfaces a given object may implement. Developers
who do not use COM s default marshaling, electing instead to write their own
proxy and marshaling routines, know at compile time all the interfaces to be
found on their objects and therefore understand exactly what marshaling code is
required. COM, in providing marshaling support for all objects, must do so at
run time.
The interface
proxy resides in the client process; the interface stub, in the
server. Together, each pair handles all marshaling for its interface. The job
of each interface proxy is to marshal arguments and unmarshal return
values and out parameters that are passed back and forth in subsequent calls to
its interface. The job of each interface stub is to unmarshal function
arguments and pass them along to the original object, then marshal the return
values and out parameters that the object returns.
Proxy and
stub communicate by means of an RPC (remote procedure call) channel, which
utilizes the system s RPC infrastructure for interprocess communication. The
RPC channel implements a single interface IRpcChannelBuffer, an internal
interface to which both interface proxies and stubs hold a pointer. The proxy
and stub call the interface to obtain a marshaling packet, send the data to
their counterpart, and destroy the packet when they are done. The interface
stub also holds a pointer to the original object.
For any given
interface, the proxy and stub are both implemented as instances of the same
class, which is listed for each interface in the system registry under the
label ProxyStubClsid32 (or ProxyStubClsid on 16-bit systems).
This entry maps the interface s IID to the CLSID of its proxy and stub objects.
When COM needs to marshal an interface, it looks in the system registry to
obtain the appropriate CLSID. The server identified by this CLSID implements
both the interface proxy and interface stub.
Most often, the class to which this CLSID refers is
automatically generated by a tool whose input is a description of the function
signatures and semantics of a given interface, written in some interface
description language. While using such a language is highly recommended and
encouraged for accuracy s sake, doing so is by no means required. Proxies and
stubs are merely Component Object Model components used by the RPC
infrastructure and, as such, can be written in any manner desired so long as
the correct external contracts are upheld. The programmer who designs a new
interface is responsible for ensuring that all interface proxies and stubs that
ever exist agree on the representation of their marshaled data.
When created, interface proxies are always aggregated
into a larger proxy, which represents the object as a whole. This object proxy
also aggregates COM s generic proxy object, which is known as the proxy
manager. The proxy manager implements two interfaces: IUnknown
A proxy
representing the object as a whole is required in the client process so that a
client can distinguish calls to the same interfaces implemented on entirely
different objects. Such a requirement does not exist in the server process,
however, where the object itself resides, because all interface stubs
communicate only with the objects for which they were created. No other
connection is possible.
Interface stubs, by contrast with interface proxies,
are not aggregated, because there is no need that they appear to some external
client to be part of a larger whole. When connected, an interface stub is given
a pointer to the server object to which it should forward method invocations
that it receives. Although it is useful to refer conceptually to a stub manager,
meaning whatever pieces of code and state in the server-side RPC infrastructure
that service the remoting of a given object, there is no direct requirement
that the code and state take any particular, well-specified form.
The first
time a client requests a pointer to an interface on a particular object, COM
loads an IClassFactory
Back in the
server process, COM now creates a new instance of the object, along with a stub
for the requested interface. This stub marshals the interface pointer back to
the client process, where another object proxy is created, this time for the
object itself. Also created is a proxy for the requested interface, a pointer
to which is returned to the client. With subsequent calls to other interfaces
on the object, COM will load the appropriate interface stubs and proxies as
needed.
When a new interface proxy is created, COM hands it a
pointer to the proxy manager s implementation of IUnknown, to which it
delegates all QueryInterface calls. Each interface proxy implements two
interfaces of its own: the interface it represents and IRpcProxyBuffer.
The interface proxy exposes its own interface directly to clients, which can
obtain its pointer by calling QueryInterface on the proxy manager. Only
COM, however, can call IRpcProxyBuffer, which it uses to connect and
disconnect the proxy to the RPC channel. A client cannot query an interface
proxy to obtain a pointer to the IRpcProxyBuffer interface.
On the server side, each interface stub implements IRpcStubBuffer,
an internal interface. The server code acting as a stub manager calls IRpcStubBuffer::Connect
and passes the interface stub the IUnknown pointer of its object.
When an interface proxy receives a method invocation,
it obtains a marshaling packet from its RPC channel through a call to IRpcChannelBuffer::GetBuffer.
The process of marshaling the arguments will copy data into the buffer. When
marshaling is complete, the interface proxy invokes IRpcChannelBuffer::SendReceive
to send the marshaled packet to the corresponding interface stub. When IRpcChannelBuffer::SendReceive
returns, the buffer into which the arguments were marshaled will have been
replaced by a new buffer containing the return values marshaled from the
interface stub. The interface proxy unmarshals the return values, invokes IRpcChannelBuffer::FreeBuffer
to free the buffer, then returns the return values to the original caller of
the method.
It is the implementation of IRpcChannelBuffer::SendReceive
that actually sends the request to the server process and that knows how to
identify the server process and, within that process, the object to which the
request should be sent. The channel implementation also knows how to forward
the request on to the appropriate stub manager in that process. The interface
stub unmarshals the arguments from the provided buffer, invokes the indicated
method on the server object, and marshals the return values back into a new
buffer, allocated by a call to IRpcchannelBuffer::GetBuffer. The channel
then transmits the return data packet back to the interface proxy, which is
still in the middle of IRpcchannelBuffer::SendReceive, which returns to
the interface proxy.
A particular instance of an interface proxy can be
used to service more than one interface, so long as two conditions are met.
First, the IIDs of the affected interfaces must be mapped to the the
appropriate ProxyStubClsid in the system registry. Second, the interface
proxy must support calls to QueryInterface from one supported interface
to the other interfaces, as usual, as well as from IUnknown and IRpcProxyBuffer.
A single instance of an interface stub can also
service more than one interface, but only if that set of interfaces has a
strict single-inheritance relationship. This restriction exists because the
stub can direct method invocations to multiple interfaces only where it knows
in advance which methods are implemented on which interfaces.
Both proxies and stubs will at various times have need
to allocate or free memory. Interface proxies, for example, will need to
allocate memory in which to return out parameters to their caller. In this
respect, interface proxies and interface stubs are just normal COM components,
in that they should use the standard task allocator (see CoGetMalloc
When to Use
You should
use COM s default implementation of IMarshal except in those very few
cases where your application has special requirements that COM s default
implementation does not address, or where you can achieve optimizations over
the marshaling code COM has provided. For examples of such special cases, see IMarshal,
When to Implement.
See Also